#include "bscpoll.h"
#include "cvector.h"

#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <WinSock2.h>
#include <Windows.h>
#else
#include <sys/select.h>
#endif


struct _bsc_poll {
	cvector_vector_type(bsc*) clients;
};


bsc_poll* create_bscpoll() {
	bsc_poll* poll = malloc(sizeof(bsc_poll));
	memset(poll, 0, sizeof(bsc_poll));
	return poll;
}

void destroy_bscpoll(bsc_poll* poll) {
	cvector_free(poll->clients);
	free(poll);
}

void bscpoll_add(bsc_poll* poll, bsc *client) {
	bsc **itr;
	for (itr = cvector_begin(poll->clients);itr != cvector_end(poll->clients); ++itr) {
		if (*itr == client) {
			return;
		}
	}

	cvector_push_back(poll->clients,client);
}

void bscpoll_remove(bsc_poll* poll, bsc *client) {
	size_t i;
	for (i = 0; i < cvector_size(poll->clients); ++i) {
		if (poll->clients[i] == client) {
			cvector_erase(poll->clients, i);
			return;
		}
	}
}

int bscpoll_wait(bsc_poll* poll, int timeout_ms) {
	struct timeval timeout;
	bsc **itr;
	fd_set readset, writeset,errset;
	int write = 0;
	int maxfdp = 0;
	char errorstr[BSC_ERRSTR_LEN];

	FD_ZERO(&readset);
	FD_ZERO(&writeset);
	FD_ZERO(&errset);

	timeout.tv_sec = timeout_ms / 1000;
	timeout.tv_usec = (timeout_ms % 1000)*1000;


	for (itr = cvector_begin(poll->clients); itr != cvector_end(poll->clients); ++itr) {

		if ((*itr)->fd > maxfdp) {
			maxfdp = (*itr)->fd;
		}

		FD_SET((*itr)->fd, &readset);
		FD_SET((*itr)->fd, &errset);

		if (!AQ_EMPTY((*itr)->outq) || (*itr)->state == BSC_STATE_CONNECTING) {
			FD_SET((*itr)->fd, &writeset);
			++write;
		}
	}

	if (write) {
		if (select(maxfdp + 1, &readset, &writeset, &errset, &timeout) < 0) {
			return EXIT_FAILURE;
		}

		for (itr = cvector_begin(poll->clients); itr != cvector_end(poll->clients); ++itr) {
			if (FD_ISSET((*itr)->fd, &readset)) {
				if ((*itr)->state == BSC_STATE_CONNECTING)
					bsc_on_connect(*itr, errorstr);

				bsc_read(*itr);
			}

			if (FD_ISSET((*itr)->fd, &writeset)) {
				if ((*itr)->state == BSC_STATE_CONNECTING)
					bsc_on_connect(*itr, errorstr);
				else
					bsc_write(*itr);
			}

			if (FD_ISSET((*itr)->fd, &errset) && (*itr)->onerror)
				(*itr)->onerror(*itr, BSC_ERROR_SOCKET);
		}

	}else{
		if (select(maxfdp + 1, &readset, NULL, &errset, &timeout) < 0) {
			return EXIT_FAILURE;
		}

		for (itr = cvector_begin(poll->clients); itr != cvector_end(poll->clients); ++itr) {
			if (FD_ISSET((*itr)->fd, &readset))
				bsc_read(*itr);

			if (FD_ISSET((*itr)->fd, &errset) && (*itr)->onerror)
				(*itr)->onerror(*itr, BSC_ERROR_SOCKET);

		}
	}
	return EXIT_SUCCESS;
}

